﻿using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using XUCore.Extensions;
using XUCore.WeChat.Enterprise.Apis.Group.Chat;
using XUCore.WeChat.Enterprise.Apis.Group.Message;
using XUCore.WeChat.Enterprise.Apis.Group.Statistic;
using XUCore.WeChat.Enterprise.Apis.Group.WelCome;
using XUCore.WeChat.Enterprise.Apis.Media;
using XUCore.WeChat.Enterprise.Apis.Member;
using XUCore.WeChat.Enterprise.Apis.Sns;
using XUCore.WeChat.Enterprise.Apis.Suite;
using XUCore.WeChat.Enterprise.Apis.Ticket;
using XUCore.WeChat.Enterprise.Apis.Token;
using XUCore.WeChat.Enterprise.Net.ServerMessages;

namespace XUCore.WeChat.Enterprise
{
    public static class Extentions
    {
        /// <summary>
        /// 添加企业微信Sdk集成
        /// </summary>
        /// <param name="services"></param>
        /// <returns></returns>
        public static IServiceCollection AddEnterpriseWeChatSdk(this IServiceCollection services)
        {
            services.AddSingleton<EnterpriseWeChatFuncs>();

            services.AddHttpApi<IEnterpriseTokenApi>();
            services.AddHttpApi<IEnterpriseTicketApi>();
            services.AddHttpApi<IEnterpriseSnsApi>();
            services.AddHttpApi<IEnterpriseMediaApi>();
            services.AddHttpApi<IEnterpriseSuiteApi>();

            services.AddHttpApi<IEnterpriseMemberApi>();
            services.AddHttpApi<IEnterpriseGroupMessageApi>();
            services.AddHttpApi<IEnterpriseGroupWelComeApi>();
            services.AddHttpApi<IEnterpriseGroupChatApi>();
            services.AddHttpApi<IEnterpriseContactStatisticApi>();
            services.AddHttpApi<IEnterpriseGroupStatisticApi>();

            services.AddSingleton<IEnterpriseWeChatTokenManager, EnterpriseWeChatTokenManager>();
            services.AddSingleton<IEnterpriseWeChatTicketManager, EnterpriseWeChatTicketManager>();
            services.AddSingleton<IEnterpriseWeChatWebSignature, EnterpriseWeChatWebSignature>();
            services.AddSingleton<IEnterpriseWeChatSuiteTicketManager, EnterpriseWeChatSuiteTicketManager>();

            return services;
        }

        /// <summary>
        /// 添加企业微信服务器事件消息处理程序
        /// </summary>
        /// <param name="services"></param>
        /// <returns></returns>
        public static IServiceCollection AddEnterpriseServerMessageHandler(this IServiceCollection services)
        {
            services.AddSingleton<EnterpriseServerMessageHandler>();
            return services;
        }

        /// <summary>
        /// 配置公众号Sdk和支付sdk配置
        /// </summary>
        /// <param name="app"></param>
        /// <param name="setupAction"></param>
        /// <returns></returns>
        public static IApplicationBuilder UseEnterpriseWeChatSdk(this IApplicationBuilder app, Action<EnterpriseWeChatFuncs> setupAction = null)
        {
            EnterpriseWeChatFuncs funcs = app.ApplicationServices.GetRequiredService<EnterpriseWeChatFuncs>();
            setupAction?.Invoke(funcs);

            //初始化配置文件里的企业配置
            if (funcs.GetEnterpriseWeChatOptions == null)
            {
                IConfiguration config = app.ApplicationServices.GetRequiredService<IConfiguration>();
                IConfigurationSection wechatConfig = config.GetSection("WeChat");
                if (wechatConfig != null)
                {
                    funcs.GetEnterpriseWeChatOptions = () =>
                    {
                        IConfigurationSection _config = config.GetSection($"{EnterpriseWeChatConsts.CONFIG_SECTION_ENTERPRISE_KEY}");
                        if (_config == null) return null;

                        var options = new List<EnterpriseWeChatOption>();
                        _config.Bind(options);
                        return options;
                    };
                }
            }
            //获取配置，可以在注入的时候改为从数据库获取
            if (funcs.GetEnterpriseWeChatAgentOptions == null)
            {
                funcs.GetEnterpriseWeChatAgentOptions = (string suiteId, string corpId, int agentId) =>
                {
                    var opt = funcs.GetEnterpriseWeChatOptions();

                    var suite = default(EnterpriseWeChatOption);

                    if (suiteId.IsEmpty())
                        suite = opt.FirstOrDefault();
                    else
                        suite = opt.FirstOrDefault(c => c.SuiteId == suiteId);

                    var agent = suite.Agents.FirstOrDefault(c => c.CorpId == corpId && c.AgentId == agentId);

                    if (agent != null) return (suite.SuiteId, suite.SuiteSecret, agent);

                    return (suiteId, "", default);
                };
            }
            return app;
        }

        /// <summary>
        /// 使用分布式缓存来存储AccessToken
        /// </summary>
        /// <param name="app"></param>
        /// <returns></returns>
        public static IApplicationBuilder UseEnterpriseWeChatDistributedCacheForAccessToken(this IApplicationBuilder app)
        {
            var funcs = app.ApplicationServices.GetRequiredService<EnterpriseWeChatFuncs>();
            var cache = app.ApplicationServices.GetRequiredService<IDistributedCache>();

            if (funcs.GetEnterpriseWeChatTicketByAppId == null)
            {
                funcs.GetEnterpriseWeChatTicketByAppId = (appid) => cache.GetString($"{EnterpriseWeChatConsts.ENTERPRISEWECHAT_CACHE_NAMESPACE}::JT::{appid}");
            }

            if (funcs.CacheEnterpriseWeChatTicket == null)
            {
                funcs.CacheEnterpriseWeChatTicket = (appid, ticket) =>
                {
                    if (string.IsNullOrEmpty(ticket))
                        throw new Exception("ticket 为空，请检查IP白名单，安全域名等设置");

                    byte[] tokenBytes = Encoding.UTF8.GetBytes(ticket);
                    cache.Set($"{EnterpriseWeChatConsts.ENTERPRISEWECHAT_CACHE_NAMESPACE}::JT::{appid}", tokenBytes, new DistributedCacheEntryOptions()
                    {
                        AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(115)
                    });
                };
            }

            if (funcs.GetEnterpriseWeChatAccessTokenByCorpId == null)
            {
                funcs.GetEnterpriseWeChatAccessTokenByCorpId = (corpid) => cache.GetString($"{EnterpriseWeChatConsts.ENTERPRISEWECHAT_CACHE_NAMESPACE}::AT::{corpid}");
            }

            if (funcs.CacheEnterpriseWeChatAccessToken == null)
            {
                funcs.CacheEnterpriseWeChatAccessToken = (corpid, token) =>
                {
                    if (string.IsNullOrEmpty(token))
                        throw new Exception("access_token 为空，请检查IP白名单，安全域名等设置");

                    byte[] tokenBytes = Encoding.UTF8.GetBytes(token);
                    cache.Set($"{EnterpriseWeChatConsts.ENTERPRISEWECHAT_CACHE_NAMESPACE}::AT::{corpid}", tokenBytes, new DistributedCacheEntryOptions()
                    {
                        AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(115)
                    });
                };
            }

            if (funcs.GetEnterpriseWeChatSuiteTicket == null)
            {
                funcs.GetEnterpriseWeChatSuiteTicket = (suiteId) => cache.GetString($"{EnterpriseWeChatConsts.ENTERPRISEWECHAT_CACHE_NAMESPACE}::ST::{suiteId}");
            }

            if (funcs.CacheEnterpriseWeChatSuiteTicket == null)
            {
                funcs.CacheEnterpriseWeChatSuiteTicket = (suiteId, suiteTicket) =>
                {
                    byte[] tokenBytes = Encoding.UTF8.GetBytes(suiteTicket);
                    cache.Set($"{EnterpriseWeChatConsts.ENTERPRISEWECHAT_CACHE_NAMESPACE}::ST::{suiteId}", tokenBytes, new DistributedCacheEntryOptions()
                    {
                        //临时ticket只有30分钟的时效，但是官方会大概10分钟推送一次
                        AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(28)
                    });
                };
            }

            return app;
        }
    }
}